package Cal;
import java.math.BigDecimal;
import java.util.Stack;
class Calculator {
    /**
     * 加减乘除优先级 括号比较特殊，要等括号里面的算完再最后算，所以括号“优先级最低”(其实最高)
     * 使用了大数BigDecimal，防止数据溢出
     * @param c
     * @return
     */
    static int zh(char c)
    {
        if(c=='('||c==')')return 0;
        if(c=='+'||c=='-')return 1;
        if(c=='*'||c=='/') return 2;
        return -1;
    }
    static BigDecimal add(BigDecimal n1,BigDecimal n2,char c)
    {
        try
        {
            if(c=='+')return n1.add(n2);
            if(c=='-')return n1.subtract(n2);
            if(c=='*')return n1.multiply(n2);
            if(c=='/')return n1.divide(n2,10, BigDecimal.ROUND_CEILING);
        }
        catch (Exception e)
        {
            return null;
        }
        return null;
    }
    /**
     * 算式计算
     * @param s
     * @return
     */
    static String jisuan(String s)
    {
        Stack<BigDecimal> nstack = new Stack<>();
        Stack cstack = new Stack<>();
        int dj,ndj;
        dj=ndj=0; //ndj是记录上一个符号是什么等级，如果这次是'-'，则用来判断是减号还是负号，如果上一个符号是数字（ndj==-1）说明这次是减号，否则是负号。
        for(int i=0;i<s.length();i++)
        {
            char si=s.charAt(i);
            if(si==')')
            {
                char tc='\0';
                while(!cstack.empty())//将括号内部的东西算完，直到碰到左括号后匹配
                {
                    tc=cstack.pop().toString().charAt(0);
                    if(tc=='(')break;
                    BigDecimal n2=nstack.pop();
                    BigDecimal n1=nstack.pop();
                    n1=add(n1,n2,tc);
                    if(n1==null)return "null";
                    nstack.push(n1);
                }
                if(tc!='(')return "Bracket mismatch";//括号不匹配，如果缺右括号的话，默认自动在算式尾部添加，缺左括号则报错
                continue;
            }
            ndj=dj;
            dj=zh(si);
            if(dj==-1||((ndj!=-1&&si=='-')))//数字为-1，或者带负号的数字，负号和减号判断规则见上
            {
                int be=i++;
                while(i<s.length()&&zh(s.charAt(i))<0)i++;
                BigDecimal n1=new BigDecimal(s.substring(be,i));
                i--;
                nstack.push(n1);
                continue;
            }
            if(dj==0)//左括号
            {
                cstack.push(si);
                continue;
            }
            if(dj>=1)//算符计算
            {
                if(cstack.empty())
                {
                    cstack.push(si);
                    continue;
                }
                char tc=cstack.peek().toString().charAt(0);
                while(zh(tc)>=dj)//入栈时如果本算符优先级小于等于栈顶算符，则先计算栈顶算符
                {
                    BigDecimal n2=nstack.pop();
                    BigDecimal n1=nstack.pop();
                    cstack.pop();
                    n1=add(n1,n2,tc);
                    if(n1==null)return "null";
                    nstack.push(n1);
                    if(!cstack.empty())tc=cstack.peek().toString().charAt(0);
                    else tc='0';
                }
                cstack.push(si);//算符入栈
            }

        }
        /**
         * 算式栈全部计算，此时优先级就是出栈顺序，直接计算即可。
         */
        while(!cstack.empty())
        {
            char tc=cstack.pop().toString().charAt(0);
            if(tc=='(')continue;
            BigDecimal n2=nstack.pop();
            BigDecimal n1=nstack.pop();
            n1=add(n1,n2,tc);
            if(n1==null)return "null";
            nstack.push(n1);
        }
        s=nstack.pop().toString();
        /**
         * 去尾巴的0
         */
        int di=s.indexOf(".");
        if(di==-1) return s;
        int i;
        for(i=s.length()-1;i>di+1;i--)
        {
            if(s.charAt(i)!='0')
            {
                break;
            }
        }
        s=s.substring(0,i+1);
        return s;
    }
}
